package pe.bf.extranet.dao.impl;

import java.math.BigInteger;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import javax.sql.DataSource;

import oracle.jdbc.OracleTypes;

import pe.bf.base.dao.impl.BaseDAOImpl;
import pe.bf.base.types.OutParameter;
import pe.bf.domain.bean.Empresa;
import pe.bf.domain.bean.Perfil;
import pe.bf.domain.bean.TipoDocumento;
import pe.bf.domain.bean.Usuario;
import pe.bf.domain.constantes.Constantes;
import pe.bf.domain.exceptions.DomainException;
import pe.bf.extranet.dao.UsuarioDAO;

/**
 * 
 * @author rfigueroa
 * 
 */
public class UsuarioDAOImpl extends BaseDAOImpl implements UsuarioDAO {

	private static final String USP_CREAR_USUARIO = "{call PKG_USUARIO.USP_CREAR_USUARIO(?,?,?,?,?,?,?,?,?,?)}";
	private static final String USP_CAMBIO_CLAVE = "{call PKG_USUARIO.USP_CAMBIO_CLAVE(?,?)}";
	private static final String USP_CREA_PERFIL = "{call PKG_USUARIO.USP_CREA_PERFIL(?,?)}";
	private static final String USP_ACTUALIZAR_USUARIO = "{call PKG_USUARIO.USP_ACTUALIZAR_USUARIO(?,?,?,?,?,?,?,?,?)}";
	private static final String USP_ELIMINAR_USUARIO = "{call PKG_USUARIO.USP_ELIMINAR_USUARIO(?)}";
	private static final String USP_BAJA_USUARIO = "{call PKG_USUARIO.USP_BAJA_USUARIO(?)}";
	private static final String USP_LISTAR_USUARIO = "{call PKG_USUARIO.USP_LISTAR_USUARIO(?,?)}";
	private static final String USP_BUSCAR_USUARIO = "{call PKG_USUARIO.USP_BUSCAR_USUARIO(?,?,?)}";//FALTA COST
	private static final String USP_LISTAR_PERFILES = "{call PKG_USUARIO.USP_LISTAR_PERFILES(?,?)}";
	

	/**
	 * 
	 * @param dataSource
	 */
	public UsuarioDAOImpl(DataSource dataSource) {
		super(dataSource);
	}

	/**
	 * @param usuario
	 * 
	 *            Este metodo crea usuarios
	 */
	@Override
	public void crearUsuario(Usuario usuario) throws DomainException {
		try {
			long idUsuario=invokeStoreProcedureGetId(USP_CREAR_USUARIO, 
					usuario.getEmpresa().getIdEmpresa(),
					usuario.getTipodocumento().getIdTipodocumento(),
					usuario.getNrodocumento(),
					usuario.getNombres(),
					usuario.getApellidos(),
					usuario.getTelefono(),
					usuario.getAnexo(),
					usuario.getEmail(),
					usuario.getClave(),
					new OutParameter(OracleTypes.NUMBER)
					);
			
			for(Perfil perfil:(List<Perfil>)usuario.getPerfils()){
				System.out.println("perfil id "+(perfil.getIdPerfil()));
				registrarPerfiles(idUsuario,perfil.getIdPerfil());	
			}
			
			
		} catch (DomainException e) {
			throw new DomainException(e);
		}
	}
	
	
	
	@Override
	public void actualizarClave(Usuario usuario) throws DomainException {
		try {
			invokeStoreProcedure(USP_CAMBIO_CLAVE, 	usuario.getIdUsuario()+"" ,	usuario.getClave());
			
		} catch (DomainException e) {
			throw new DomainException(e);
		}
	}

	/**
	 * Este metodo actualiza usuarios
	 * 
	 * @param usuario
	 */
	@Override
	public void actualizarUsuario(Usuario usuario) throws DomainException {
		try {
			invokeStoreProcedure(USP_ACTUALIZAR_USUARIO, 
					usuario.getIdUsuario(),
					usuario.getTipodocumento().getIdTipodocumento(),
					usuario.getNrodocumento(),
					usuario.getNombres(),
					usuario.getApellidos(),
					usuario.getTelefono(),
					usuario.getAnexo(),
					usuario.getEmail(),
					usuario.getClave()
					);
			
			for(Perfil perfil:(List<Perfil>)usuario.getPerfils()){
				
				registrarPerfiles(usuario.getIdUsuario(),perfil.getIdPerfil());	
			}
			
		} catch (DomainException e) {
			throw new DomainException(e);
		}
	}
	
	@Override
	public void registrarPerfiles(long idUsuario,Long idPerfil) throws DomainException {
		try {
			invokeStoreProcedure(USP_CREA_PERFIL, 
					idUsuario, 
					idPerfil
					);
		} catch (DomainException e) {
			throw new DomainException(e);
		}
	}
	

	/**
	 * Este metodo actualiza usuarios
	 * 
	 * @param usuario
	 */
	@Override
	public void actualizarUsuario(List<Usuario> usuario) throws DomainException {
		for (Usuario usu : usuario) {
			actualizarUsuario(usu);
		}
	}

	/**
	 * Este metodo actualiza usuarios
	 * 
	 * @param id
	 */
	@Override
	public void elimiarUsuario(long id) throws DomainException {
		try {
			invokeStoreProcedure(USP_ELIMINAR_USUARIO, id);
		} catch (DomainException e) {
			throw new DomainException(e);
		}
	}
	
	
	/**
	 * Este metodo da de baja usuarios
	 * 
	 * @param id
	 */
	@Override
	public void bajaUsuario(long id) throws DomainException {
		try {
			invokeStoreProcedure(USP_BAJA_USUARIO, id);
		} catch (DomainException e) {
			throw new DomainException(e);
		}
	}
	

	/**
	 * Lista los usuarios por empresa
	 * 
	 * @param idEmpresa
	 */
	@Override
	public List<Usuario> listarUsuarios(BigInteger idEmpresa) throws DomainException {

		List<Usuario> usuarioList = null;
		CallableStatement cal = null;
		try {
			cal = invokeStoreProcedureCallable(USP_LISTAR_USUARIO, idEmpresa+"",new OutParameter(OracleTypes.CURSOR));//porque se puso una constante aqui?
			ResultSet resultSet = (ResultSet) cal.getObject(2);
			usuarioList = new ArrayList<Usuario>();
			while (resultSet.next()){
				Usuario usuario = new Usuario();
				usuario.setIdUsuario(resultSet.getLong("ID_USUARIO"));
				usuario.setTipodocumento(new TipoDocumento(resultSet.getLong("ID_TIPODOCUMENTO"),resultSet.getString("DESCRIPCION")));
				usuario.setNombres(resultSet.getString("NOMBRES"));
				usuario.setApellidos(resultSet.getString("APELLIDOS"));
				usuario.setNrodocumento(resultSet.getString("NRODOCUMENTO"));
				usuario.setTelefono(resultSet.getString("TELEFONO"));
				usuario.setAnexo(resultSet.getString("ANEXO"));
				usuario.setClave(resultSet.getString("CLAVE"));
				usuario.setEstado(resultSet.getString("ESTADO"));
				usuario.setEmail(resultSet.getString("EMAIL"));
				usuario.setFechacreacion(resultSet.getDate("FECHACREACION"));
				usuario.setUltimoAcceso(resultSet.getDate("ULTIMOACCESO"));
				usuarioList.add(usuario);
			}
		}catch (SQLException e) {
			e.printStackTrace();
			throw new DomainException(e);
		} finally{
			try {
				cal.getConnection().close();
				cal.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
		return usuarioList;
	}

	@Override
	public Usuario buscarUsuario(Usuario usuarioFiltro) throws DomainException{

		List<Usuario> usuarioList = null;
		CallableStatement cal = null;
		try {
			cal = invokeStoreProcedureCallable(USP_BUSCAR_USUARIO, usuarioFiltro.getNrodocumento() ,usuarioFiltro.getClave(),new OutParameter(OracleTypes.CURSOR));//porque se puso una constante aqui?
			ResultSet resultSet = (ResultSet) cal.getObject(3);
			usuarioList = new ArrayList<Usuario>();
			System.out.println("por entrar con usuario " + usuarioFiltro.getIdUsuario());
			while (resultSet.next()){
				Usuario usuario = new Usuario();
				usuario.setIdUsuario(resultSet.getLong("ID_USUARIO"));
				Empresa empresa=new Empresa();
				empresa.setIdEmpresa(resultSet.getLong("ID_EMPRESA"));
				empresa.setNombres(resultSet.getString("NOMBRES_EMPRESA"));   
				empresa.setRuc(resultSet.getString("RUC_EMPRESA")); 
				usuario.setEmpresa(empresa);   
				usuario.setTipodocumento(new TipoDocumento(resultSet.getLong("ID_TIPODOCUMENTO"),resultSet.getString("DESCRIPCION_TD")));
				usuario.setNombres(resultSet.getString("NOMBRES"));
				usuario.setTelefono(resultSet.getString("TELEFONO"));
				usuario.setAnexo(resultSet.getString("ANEXO"));
				usuario.setEmail(resultSet.getString("EMAIL"));
				usuario.setClave(resultSet.getString("CLAVE"));
				usuario.setEstado(resultSet.getString("ESTADO"));
				usuario.setFechacreacion(resultSet.getDate("FECHACREACION"));   
				usuario.setPerfilesString(obtenerPerfiles(usuario.getIdUsuario()));
				return usuario;
			}
		}catch (SQLException e) {
			e.printStackTrace();
			throw new DomainException(e);
		} finally{
			try {
				cal.getConnection().close();
				cal.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		} 
		return null;
	}

	public String  obtenerPerfiles(long usuario) throws DomainException {
		String perfilList = "";
		CallableStatement cal = null;
		try { 
			

				cal = invokeStoreProcedureCallable(USP_LISTAR_PERFILES, usuario+"",new OutParameter(OracleTypes.CURSOR));
				ResultSet resultSet = (ResultSet) cal.getObject(2);  
				while (resultSet.next()) {
					Perfil perfil = new Perfil();
					perfil.setIdPerfil(resultSet.getLong("ID_PERFIL"));
					perfil.setDescripcion(resultSet.getString("DESCRIPCION"));
					perfilList=perfilList+resultSet.getLong("ID_PERFIL")+"-"; 
				} 
				return perfilList;
  
		} catch (SQLException e) {
			e.printStackTrace();
			throw new DomainException(e);
			
		} finally{
			try {
				cal.getConnection().close();
				cal.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		} 
		
	}
	
	public List<Usuario> obtenerPerfiles(List<Usuario> usuarios) throws DomainException {
		List<Usuario> lista = new ArrayList();
		List<Perfil> perfilList = null;
		CallableStatement cal = null;
		
			
			for(Usuario usuario:usuarios){
				try { 
				cal = invokeStoreProcedureCallable(USP_LISTAR_PERFILES, usuario.getIdUsuario()+"",new OutParameter(OracleTypes.CURSOR));
				ResultSet resultSet = (ResultSet) cal.getObject(2); 
				perfilList = new ArrayList<Perfil>();
				while (resultSet.next()) {
					Perfil perfil = new Perfil();
					perfil.setIdPerfil(resultSet.getLong("ID_PERFIL"));
					perfil.setDescripcion(resultSet.getString("DESCRIPCION"));
					perfilList.add(perfil);
				} 
				usuario.setPerfils(perfilList);
				} catch (SQLException e) {
					throw new DomainException(e);
				} finally{
					try {
						lista.add(usuario);
						cal.getConnection().close();
						cal.close();
					} catch (SQLException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					
				} 
				
				
			} 
	
		return lista;
	}
	
}
